﻿#include "etools.h"
#include <QString>
#include <QRegExp>
#include <QStringList>
#include <qnamespace.h>
#include <QtMath>
#include <QDebug>
#include <QList>
#include <QComboBox>
#include <QWidget>
#include <QListView>


/*对应的键值对处理， 要注意的是顺序问题， 如 S 和 ms  因为ms之中也包括了S   把s写在ms前则可能会出现错误的检测结果*/
ETOOLS::Map ETOOLS::e_map[] =
{
    /*频率*/
#if FRE_MODE == 1
    { "GHZ", 1e9 },
    { "MHZ", 1e6 },
    { "KHZ", 1e3 },
    { "HZ",  1   },
#elif FRE_MODE == 2
    { "GHZ", 1073741824ul },
    { "MHZ", 1048576ul },
    { "KHZ", 1024 },
    { "HZ",  1 },
#endif
    /*功率*/
    { "DBM", 1 },
    { "DB",  1 },

    /*时间, 以US为基准*/
    { "US",  1   },
    { "MS",  1e3 },
    { "S",   1e6 },

    /*电压, 以MV为基准*/
    { "MV", 1   },
    { "V" , 1e3 },


    MAP_LIST_END
};


/**
 * @brief ETOOLS::numberToStringGMK 数字转换为带单位的字符串
 * @param src                       需要转换的数据
 * @param rate                      进率， 如1000， 1024等
 * @param precision                 小数点后保留几位小数（注意，如果是0的话，会被舍弃，如precision=5， 转换后字符串为100.20000， 返回的会是100.2 ）
 * @return                          转换后的字符串， 形式为 xxx M等
 */
QString ETOOLS::numberToStringGMK(const double &src, int rate, int precision)
{
    QString str;
    QString format = "";
    int G = rate * rate * rate;
    int M = rate * rate;
    int K = rate;

    if(src / G > 1)
    {
        str = QString("%1").arg( QString::number( double(src) / G, 'f', precision) );
        format = " G";
    }
    else if(src / M > 1)
    {
        str = QString("%1").arg(QString::number( double(src)  / M, 'f', precision));
        format = " M";
    }
    else if(src / K > 1)
    {
        str = QString("%1").arg( QString::number( double(src) / K, 'f', precision));
        format = " K";
    }
    else
    {
        str = QString("%1").arg(QString::number(src, 'f', precision));
        format = " "; //让没有单位的数据后边也加上个空格， 以便格式对齐
    }

    QRegExp reg("\\.");
    if(str.indexOf( reg ) > -1)
    {
        QRegExp reg2( "\\.?0+$" );
        return str.replace( reg2, "" ) + format;
    }
    return str + format;
}


/**
 * @brief ETOOLS::regText
 * @param src               要解析的字符串
 * @param split             单位
 * @param value             用作返回的值，
 * @param isCaseInsensitive true 大小写不敏感   false 大小写敏感
 * @return  true 已匹配    false 未匹配
 */
bool ETOOLS::regText(const QString &src, const Map &map, double &value, bool isCaseInsensitive)
{
    Qt::CaseSensitivity cs;
    if(isCaseInsensitive)   //是否区分大小写
    {
        cs = Qt::CaseInsensitive;
    }
    else
    {
        cs = Qt::CaseSensitive;
    }

    QRegExp reg1(QString("(-?[0-9\\.]+)\\s{0,10}(%1)").arg(map.key), cs);
    if(reg1.indexIn( src ) > -1)    //正则已匹配
    {
        value = (reg1.capturedTexts().at(1).toDouble()) * map.val;
        return true;
    }

    return false;
}


/**
 * @brief ETOOLS::stringToNumber   字符串转数据
 * @param src                   要转换的字符串
 * @param value                 输出参数，经过转换后的double类型数据
 * @param isCaseInsensitive     true: 字符串中，参数无论大小写均可以匹配   false: 严格按照m_map的定义执行，大小写敏感
 * @return                      true: 解析成功  false:解析失败
 */
bool ETOOLS::stringToNumber(const QString &src, double &value, bool isCaseInsensitive)
{
    int count = sizeof (e_map)/sizeof (Map);
    for(int i=0; i<count; i++)
    {
        if( regText( src,  e_map[i], value, isCaseInsensitive) )
        {
            return true;
        }
    }
    return false;
}


/**
 * @brief ETOOLS::comboBoxAddView   为下拉框加上委托， 使得其可以适用更多CSS
 * @param widget                    为哪一个窗口的下拉框增加委托
 * @param max_show_count            下拉框每页最多显示条数
 */
void ETOOLS::comboBoxAddView(QWidget *widget, int max_show_count)
{
    QList<QComboBox*> com_list = widget->findChildren<QComboBox *>();
    for(int i=0; i<com_list.count(); i++)
    {
        com_list[i]->setView( new QListView );
        com_list[i]->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); //根据需要。出现滚动条
        com_list[i]->setMaxVisibleItems(max_show_count);
    }
}


/**
 * @brief ETOOLS::comboBoxDisabled  禁用下拉框的某些选项
 * @param com                       要操作的下拉框指针
 * @param arr                       要禁用的的下标列表 如要禁用 下标为0  2， 3  则传入QList<int>() << 0 << 2 << 3;
 */
void ETOOLS::comboBoxEnabled(QComboBox *com, const QList<int> &arr, bool mode)
{
    QVariant v;
    if(mode)
        v.setValue(-1);
    else
        v.setValue(0);

    for(int i=0; i<arr.count(); i++)
    {
        QModelIndex index = com->model()->index(arr.at(i), 0);
        com->model()->setData(index, v, Qt::UserRole - 1);
    }
}


/**
 * @brief ETOOLS::doubleToStr       把double数据转换成字符串，可以指定精度， 特点是去掉多余的0， 如100.5610 返回的即是 100.561
 * @param src                       要进行转换的数据
 * @param precision                 小数点后保留几位精度
 * @return                          转换后的字符串
 */
QString ETOOLS::doubleToStr(const double &src, int precision)
{
    QString str = QString::number( src, 'f',  precision);

    QRegExp reg("\\.");
    if(str.indexOf( reg ) > -1)
    {
        QRegExp reg2( "\\.?0+$" );
        return str.replace( reg2, "" );
    }

    return str;
}


#ifdef EDEBUG_OUTPUT
void ETOOLS::EDEBUG( int flag, const char* format, ...)
{
    char buffer[DEBUG_BUFFER_MAX_LENGTH + 1]={0};
    va_list arg;
    va_start (arg, format);

    vsnprintf(buffer, DEBUG_BUFFER_MAX_LENGTH, format, arg);
    va_end (arg);

    QDateTime dt=QDateTime::currentDateTime();
    QString str=dt.toString("yyyy-mm-dd hh:mm:ss:zzz");
    QByteArray by = str.toLatin1();

    switch (flag)
    {
        case 0 : qDebug( "\033[1;36m[ %s ]  \033[0m  ---  %s",           by.data(), buffer ); break;   // 默认颜色
        case 1 : qDebug( "\033[1;36m[ %s ]  ---  \033[1;32m%s\033[0m", by.data(), buffer ); break;   // 执行成功 绿色
        case 2 : qDebug( "\033[1;36m[ %s ]  ---  \033[1;33m%s\033[0m", by.data(), buffer ); break;   // 执行警告 黄色
        case 3 : qDebug( "\033[1;36m[ %s ]  ---  \033[1;31m%s\033[0m", by.data(), buffer ); break;   // 执行错误 红色
    }
    fflush(stdout);
}

#else

void ETOOLS::EDEBUG(int flag, const char* format, ...){}

#endif
